﻿// Inner Fire 游戏引擎库
// Assets - 资源管理器
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：框架层(5)
// 用于管理资源
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-01-14

#include "assets.h"
#include <element.h>
#include <klog.h>
#include <xml_reader.h>

using namespace ikit;

namespace ifire::game {
// 用于单例模式
Assets* Assets::instance_ = nullptr;

Assets::Assets(GameManager* game_manager, const ikit::XmlNode& root)
    : game_manager_(game_manager) {
  instance_ = this;

  // 载入材质
  root.ForeachPaths("Material", [this](const char* f) { LoadMaterials(f); });
  // 载入贴图
  root.ForeachPaths("Texture", [this](const char* f) { LoadTextures(f); });
  // 载入模型
  root.ForeachPaths("Model", [this](const char* f) { LoadModels(f); });
  // 载入动画
  root.ForeachPaths("Animation", [this](const char* f) { LoadAnimations(f); });
  // 载入Blend动画
  root.ForeachPaths("Blend", [this](const char* f) { LoadBlends(f); });
  // 载入地图（在这个之前，要保证地图配置已经加载）
  root.ForeachPaths("Map", [this](const char* f) { LoadMaps(f); });
  // 载入Shader
  root.ForeachPaths("Shader", [this](const char* f) { LoadShaders(f); });
}

void Assets::LoadMaterials(const eastl::string_view& filename) {
  LoadFile(filename, "Material", materials_);
}

void Assets::LoadModels(const eastl::string_view& filename) {
  LoadFile(filename, "Model", models_);
}

void Assets::LoadAnimations(const eastl::string_view& filename) {
  LoadFile(filename, "Animation", animations_);
}

void Assets::LoadBlends(const eastl::string_view& filename) {
  LoadFile(filename, "Blend", blends_);
}

void Assets::LoadMaps(const eastl::string_view& filename) {
  LoadFile(filename, "Map", maps_);
}

void Assets::LoadShaders(const eastl::string_view& filename) {
  LoadFile(filename, "Shader", shaders_);
}

void Assets::LoadTextures(const eastl::string_view& filename) {
  LoadFile(filename, "Texture", textures_);
}

Material* Assets::GetMaterial(ikit::sstr name) {
  return ikit::get_item_by_name(materials_, name, default_material_);
}

Texture* Assets::GetTexture(ikit::sstr name) {
  return ikit::get_item_by_name(textures_, name, default_diffuse_);
}

Model* Assets::GetModel(ikit::sstr name) {
  return ikit::get_item_by_name(models_, name);
}

Animation* Assets::GetAnimation(ikit::sstr name, bool is_ready) {
  return Resource::GetByName(animations_, name, is_ready);
}

AnimationClip* Assets::GetClip(ikit::sstr name, bool is_ready) {
  // 常规检查
  if (name.empty()) return nullptr;

  // 将名称分级
  ikit::str_element e(name);
  // 得到Animation
  auto anim = GetAnimation(e.name, is_ready);
  if (!anim) {
    return nullptr;
  }
  // 查找Clip有一个和其它东西都不一样的地方，Clip必须要载入之后才能找到，所以这里必须Load
  // 这里做改进，必然会创建一个Default，以后如果使用，才载入，不然每次都载入，这无法接受

  // 如果没有指定，返回第一个，否则查找指定项目
  return e.value.empty() ? anim->First() : anim->FindClip(name);
}

const dx::DxSubmesh& Assets::GetMesh(ikit::sstr name) {
  auto pair = str_element(name);
  // 通过名称查找Model
  auto model = GetModel(pair.name);
  if (model == nullptr) {
    KERROR("*Assets* Unable find model of mesh: %s / %s", pair.name.c_str(),
        name.c_str());
    return dx::DxSubmesh::EMPTY;
  }

  // 如果没有指定子项目，返回第1个
  if (pair.value.empty()) {
    return model->GetMesh()->DefaultSubmesh();
  } else {
    return model->GetMesh()->GetSubMesh(pair.value);
  }
}

AnimationBlend* Assets::GetBlend(ikit::sstr name, bool is_ready) {
  return Resource::GetByName(blends_, name, is_ready);
}

Map* Assets::GetMap(ikit::sstr name, bool is_ready) {
  return Resource::GetByName(maps_, name, is_ready);
}

Shader* Assets::GetShader(ikit::sstr name) {
  return ikit::get_item_by_name(shaders_, name);
}

void Assets::SetupDefaultAssets() {
  default_material_ = GetMaterial("SYS_DEFAULT_MATERIAL");
  default_diffuse_ = GetTexture("SYS_DEFAULT_DIFFUSE");
  empty_normal_ = GetTexture("SYS_EMPTY_NORMAL");
}

void Assets::Setup() {
  Resource::Setup(animations_);
  Resource::Setup(blends_);
  Resource::Setup(models_);
}

} // namespace ifire::game